import {_decorator, Asset, AssetManager, Component, Node, Vec3, tween } from "cc"
const { ccclass, property } = _decorator;
/**
 * 莫非java中的线程睡眠，这里主要采用异步实现
 * @param delay 
 * @param call 
 * @param caller 
 * @param params 
 * @returns 
 */
function Sleep(delay:number,call?:any,caller?:any,...params):Promise<void>{
    return new Promise(resolve=>{
        let dt:any = setTimeout(()=>{
            clearTimeout(dt)
            dt=null;
            call && call.apply(caller,...params)
            resolve();
        },delay)
    })
}

function getAPI(clasName:string,method?:string,...params):any{
    const cls:any = getClass(window,clasName)
    if(cls && method){
        const methArr:string[]=method.split(".")
        let methodCall:any=cls[methArr[0]]  
        for(let i=1;i<methArr.length;i++){
            if(!methodCall)break
            methodCall=methodCall[methArr[i]]
        }
        return params.length > 0 ? methodCall.call(cls,...params) : methodCall.apply(cls)
    }
    return cls
}

function getClass(wind:Window,clasName:string):any{
    if(!wind[clasName])getClass(wind.parent,clasName)
    return wind[clasName]
}
function getMethod(obj:any,method:string,...params):any{
    if(obj && obj[method]){
        return params.length > 0  ? obj[method].apply(obj,...params) : obj[method].apply(obj) 
    }
    return null
}






//==========================================UIManager================================
export enum UILayerIndex{
    BottomLayer=0,
    UIlayer,
    PopupLayer,
    TopLayer,
    SpareLayer,
    SpecialLayer,
    AdvLayer,
    UIRoot,
}
export enum SocketConst{
    CONNECT_STATUS="connect_stuts",//socket 链接状态，是否显示
    CONNECTED="connected",//socket 链接完成
    DISCONNECTED="disconnected",//socket 链接断开
    ERROR="error_connected",//socket 链接错误 返回code,route, value 三个参数

}

export enum GameConst{
    GAME_SHOW="game_show",//游戏进入前台
    GAME_HIDE="game_hide",//游戏进入后台
    GAME_SUB_MESSAGE="game_sub_message",//子游戏消息列表
}

export enum UIWindowMessage{
    OpenUI="on_open_ui",        //打开UI 
    CloseUI="on_close_ui",      //关闭UI 
}

export class Logger{
    static Log(...params):void{return getAPI("Logger","Log",...params)} 
    static Error(...params):void{return getAPI("Logger","Error",...params)}
    static Warn(...params):void{return getAPI("Logger","Warn",...params)}
    static log(...params):void{return getAPI("Logger","log",...params)}
    static error(...params):void{return getAPI("Logger","error",...params)}
    static warn(...params):void{return getAPI("Logger","warn",...params)}
}


export class Message{
    static sendOnce(msg:string,...params:any){return getAPI("Message","sendOnce",msg,...params)}
    static addOnce(msg:string,callFun:any,caller:any){return getAPI("Message","addOnce",msg,callFun,caller)}
    static removeOnce(msg:string){return getAPI("Message","removeOnce",msg)}
    static send(msg:string,...params:any){return getAPI("Message","send",msg,...params)}
    static add(msg:string,callFun:any,caller:any){return getAPI("Message","add",msg,callFun,caller)}
    static remove(msg:string,callFun:any,caller:any){return getAPI("Message","remove",msg,callFun,caller)}
    static addGroup(group:string,msg:string,callFun:any,caller:any){return getAPI("Message","addGroup",group,msg,callFun,caller)}
    static sendGroup(group:string,msg:string,...params:any){return getAPI("Message","sendGroup",group,msg,...params)}
    static removeGroupMsg(group:string,msg:string,callFun:any,caller:any){return getAPI("Message","removeGroupMsg",group,msg,callFun,caller)}
    static removeGroup(group:string){return getAPI("Message","removeGroup",group)}
}

//========================单例=========================
export class Singleton{
    public static getInstance<T extends Singleton>(this: (new () => T) | typeof Singleton): T {
        return getAPI("Singleton","getInstance")
    }
    protected init(){
        //子类实现
    }
}


@ccclass('SingletonComponent')
export class SingletonComponent extends Component {
    public static getInstance<T extends SingletonComponent>(this: (new () => T) | typeof SingletonComponent): T {
        return getAPI("Singleton","getInstance")
    }
    protected init(){
        //子类实现
    }
}
export class ObjectPool{
    public static getObj(cls:any):any{return getAPI("ObjectPool","getObj",cls)}
    public static returnObj(obj:any){return getAPI("ObjectPool","returnObj",obj)}
}
export class SystemParams{
    static getInstance(): SystemParams {return getAPI("SystemParams","getInstance")}
    /**
     * 添加bundle版本
     * @param key       bundle对应的key
     * @param value     对应的value
     */
    public putBundleVerison(key:string,value:any){return getMethod(this,"putBundleVerison",key,value)} 
    /**
     * 获取bundle版本数据
     * @param key 
     * @returns 
     */
    public getBundleVerison(key:string):any{return getMethod(this,"getBundleVerison",key)}
    /**
     * 设置数据，方便全局保存并获取
     * @param key 
     * @param value 
     * @returns 
     */
    public setValue(key:string,value:any){return getMethod(this,"setValue",key,value)}
    /**
     * 获取数据，
     * @param key 
     * @returns 
     */
    public getValue(key:string):any{return getMethod(this,"getValue",key)}
    

}
export class UIManager{
    static getInstance(): UIManager {return getAPI("UIManager","getInstance")}
    /** 获取游戏层级节点 */
    getLayer(index:UILayerIndex=UILayerIndex.BottomLayer):Node{return getMethod(this,"getLayer",index)} 
    /** 显示当前UI */
    show<T extends Component>(bundleName:string,path:string,parent:UILayerIndex|Node|null=null,comp:{new():T}=null,isEffect:boolean=true,duration: number=0.3,values?:any):Promise<Node>{
        return getMethod(this,"show",bundleName,path,parent,comp,isEffect,duration,values)
    }
    /** 隐藏当前UI */
    hide(path:string,isEffect:boolean=true,duration: number=0.3):Promise<boolean>{return getMethod(this,"hide",path,isEffect,duration)}
    /** 判断当前UI是否存在 */
    has(path?:string){return getMethod(this,"has",path)}
    /** 获取当前UI */
    getUI(path:string):Promise<Node>{return getMethod(this,"getUI",path)}
    
}

export class LoaderBundle{
    /** 当前loade是否加载 */
    public get isUse():boolean{return getMethod(this,"isUse")}
    /** 获取当前加载路径 */
    public get path():string{return getMethod(this,"path")}
     /** bundle数据 */
    public get bundle():AssetManager.Bundle{return getMethod(this,"bundle")}
    /** 获取参数 */
    public get params():any{return getMethod(this,"params")}
    /** 清空 LoaderBundle */
    public clear(){return getMethod(this,"clear")}
    /** 加载bandle 数据 */
    public loadBundle(path:string,params:any,progress:(prv: number, total: number, item: LoaderBundle)=>void,finish:(loader:LoaderBundle)=>void){
        return getMethod(this,"loadBundle",path,...params,progress,finish)
    }
    /** 开始加载 */
    public load<T extends Asset>(path:string,type:{new():T}):Promise<T>{return getMethod(this,"load",path,type)}
}
export class LoaderManager{
    static getInstance(): LoaderManager {return getAPI("LoaderManager","getInstance")}
    /** 获取已经加载的bundle */
    public getLoaderBundle(path:string):LoaderBundle{return getMethod(this,"getLoaderBundle",path)}
    /** 开始加载bundle */
    public loadBundle(path:string,params:any,progress:(prv: number, total: number, item:LoaderBundle)=>void,finish:(loader:LoaderBundle)=>void){
        return getMethod(this,"loadBundle",path,...params,progress,finish)
    }
    /** 
     * 带传参数加载bundle
     * params {path，version}
     */
    public LoadBundleByParams(params:any,progress:(prv: number, total: number, item:LoaderBundle)=>void,finish:(loader:LoaderBundle)=>void){
        return getMethod(this,"LoadBundleByParams",params,progress,finish)
    }
    /**
     * 获取加载的bund中的数据
     * @param bundleName 
     * @param path 
     * @param type 
     * @returns 
     */
    public getType<T extends {new():Asset}>(bundleName:string,path:string,type:T):Promise<Asset>{
        return getMethod(this,"getType",bundleName,path,type)
    }
    /** 释放LoaderBundle */
    public release(path:string){
        return getMethod(this,"release",path)
    }
}
export class EffectManager{
    static getInstance(): EffectManager {return getAPI("EffectManager","getInstance")}
    /**
     * 打开一个UI界面展示效果，UIManager中的show方法来打开的UI界面都是自动调用此方法的
     * @param main 
     * @param duration 
     * @returns 
     */
    public openUIWindow(main:Node,duration: number=0.3):Promise<void>{return getMethod(this,"openUIWindow",main,duration)}
    /**
     * 关闭一个UI界面展示效果，UIManager中的hide方法来打开的UI界面都是自动调用此方法的
     * @param main 
     * @param duration 
     * @returns 
     */
    public closeUIWindow(main:Node,duration: number=0.3):Promise<void>{return getMethod(this,"closeUIWindow",main,duration)}
    
}

export class ConfigManager{
    static getInstance(): ConfigManager {return getAPI("ConfigManager","getInstance")}
    public get debug():boolean{return getMethod(this,"debug")}
    public set debug(value:boolean){getMethod(this,"debug",value)}

    public loadBundle(path:string):Promise<AssetManager.Bundle>{return getMethod(this,"loadBundle",path)} 
    public addBundle(bundle:AssetManager.Bundle){return getMethod(this,"addBundle",bundle)}
    public removeBundle(name:string){return getMethod(this,"removeBundle",name)}
    getConfig<T extends {new()}>(name:string,where:any,type?:T,bundleName?:string):any{return getMethod(this,"getConfig",bundleName,name,where,type)}
    getConfigList<T extends {new()}>(name:string,where:any,type?:T,bundleName?:string):any[]{return getMethod(this,"getConfigList",bundleName,name,where,type)}

}

export class HttpManager{
    public static get url():string{return getMethod(this,"url")}
    public static set url(value:string){getMethod(this,"url",value)}
    public static getURL(path:string):string{return getMethod(this,"getURL",path)}
    public static post(path:string,data:any={}):Promise<any>{
        return getMethod(this,"post",path,data)
    }
    public static get(path:string,data:any={}):Promise<any>{return getMethod(this,"get",path,data)}

}
export class Network{
    static getInstance(): Network {return getAPI("Network","getInstance")}
    /** 设置token验证 */
    public setTokenCode(value: number){return getMethod(this,"setTokenCode",value)} 
    /** 游戏推出发送协议 */
    public exitGame(code: number, param: any = {}):Promise<void>{return getMethod(this,"exitGame",code,param)}
    /** 游戏协议注册回调 */
    public registhandle(cmd: string | number, methods?: Function){return getMethod(this,"registhandle",cmd,methods)}
    /** 移除网络监听 */
    public removehandle(cmd: string | number, methods?: Function){return getMethod(this,"removehandle",cmd,methods)}
    /** 重新链接 */
    public reSetConnect() { return getMethod(this,"reSetConnect")}
    /** 自动链接服务器 */
    public async autoConnectToServer(showLoading?:boolean) {return getMethod(this,"autoConnectToServer",showLoading)}
    /** 网络链接成功后发送数据 */
    public send(proto: number|string, msg: any, callback?: Function):Promise<void> {return getMethod(this,"send",proto,msg,callback)}
    /** 强制关闭socket */
    public close() {return getMethod(this,"close")}
    /** 判断当前socket是否链接 */
    get isOpen():boolean{return getMethod(this,"isOpen")}
    /** 获取服务器时间戳 */
    get serTime():number {return getMethod(this,"serTime")}


}

//=============================================常用工具=====================================================================
export class TimeTools{
    /** 是否使用服务器时间 */
    public static get isUseSerTime():boolean{return getAPI("TimeTools","isUseSerTime")}
    public static set isUseSerTime(value:boolean){getAPI("TimeTools","isUseSerTime",value)}
    /** 当前时间戳，从服务器 心跳包中获取服务器当前时间戳 */
    public static get timestamp():number{return getAPI("TimeTools","timestamp")}
    public static set timestamp(value:number){getAPI("TimeTools","timestamp",value)}
    /**
	 * 本地时间和服务器时间查找
	 */ 
    public static get timeDifference():number{return getAPI("TimeTools","timeDifference")}
    public static set timeDifference(value:number){getAPI("TimeTools","timeDifference",value)}
    /** 待定，time 单位是秒 */
    public static Sleep(time:number):Promise<void>{return getAPI("TimeTools","Sleep",time)}
    /**
	 * 获取当前时间戳
	 * @example
	 * TimeUtil.getTimestamp(); // 1614616955186
	 */
    public static getTimestamp(): number{return getAPI("TimeTools","getTimestamp")}
    /**
	 * 获取当前日期（年/月/日）
	 * @example
	 * TimeUtil.getDate(); // "2021/3/2"
	 */
	public static getDate(): string {return getAPI("TimeTools","getDate")}
    /**
	 * 获取当天指定时间的时间戳
	 * @param hour 时
	 * @param minute 分
	 * @param second 秒
	 * @example
	 * const time = TimeUtil.getTargetTimestamp(10, 20, 30); // 1601259630000
	 * new Date(time).toLocaleString(); // "上午10:20:30"
	 */
	public static getTargetTimestamp(hour: number = 0, minute: number = 0, second: number = 0): number {return getAPI("TimeTools","getTargetTimestamp",hour,minute,second)}
    /**
     * 倒计时转换
     * @param times 
     * @returns 
     */
    public static downTime(times:number){return getAPI("TimeTools","downTime",times)}
    /**
	 * 将时间戳转成年月日格式
	 * @param timestamp 
	 * @returns  
	 */
	public static convertTimeTo(timestamp:number):string{return getAPI("TimeTools","convertTimeTo",timestamp)}

}
export class GameUtils{
    /**
     * 打开一个网址
     * @param url 
     */
    static openURL(url:string){return getAPI("GameUtils","openURL",url)}
     /**
     * 将字节转byte,kb,mb,GB
     * @param byte 
     * @returns 
     */
    public static convertByte(byte: number):string{return getAPI("GameUtils","convertByte",byte)}
      /**
     * 金额数字转换,千分号+2个小数
     */
    public static getAmountToString(num: number, fixed: number = 2): string {return getAPI("GameUtils","getAmountToString",num,fixed)}
    /**
     * 字符串是否为空
     * @param str 字符串
     * @param type 去空格标识
     * @returns
     */
    public static isEmpty(str: string): boolean {return getAPI("GameUtils","isEmpty",str)}
    /**
     * 去掉字符串中空格
     * @param str 字符串
     * @param type 去空格标识
     * @returns
     */
    public static trim(str: string, type: number = 0): string {return getAPI("GameUtils","trim",str,type)}
    /**
     * 获取bundle资源路径
     * 实现代码
     *  public static getBundlePath(bundleName:string):string{
     *    if(DEBUG)return bundleName
     *   if(sys.isNative){
     *       return `${native.fileUtils.getWritablePath()}bundles/${bundleName}`;
     *   }
     *   return `${localStorage.getItem("ResURL")}/${GameUtils.getPlatform()}/${bundleName}`
     *  }
     * @param bundleName 
     * @returns 
     */
    public static getBundlePath(bundleName:string):string{return getAPI("GameUtils","getBundlePath",bundleName)}
    /**
     * 获取平台字符串
     * @returns 
     */
    public static getPlatform():string{return getAPI("GameUtils","getBugetPlatformndlePath")}

}
